package com.naiterui.ehp.bs.doctor.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.naiterui.common.repository.page.CustomizedPageConvertor;
import com.naiterui.common.repository.page.Page;
import com.naiterui.common.repository.page.PageParamVO;
import com.naiterui.common.repository.page.PageVO;
import com.naiterui.ehp.bp.bo.consult.VideoConsultBO;
import com.naiterui.ehp.bp.bo.esign.EsignDoctorBO;
import com.naiterui.ehp.bp.bo.recommend.DrBaseBusinessDataBO;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.constants.PaQrCodeEnum;
import com.naiterui.ehp.bp.domain.BannerInfo;
import com.naiterui.ehp.bp.domain.Department;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.domain.DrMessageConsultOrder;
import com.naiterui.ehp.bp.domain.DrVideoConsult;
import com.naiterui.ehp.bp.domain.Hospital;
import com.naiterui.ehp.bp.domain.MessagePushHistory;
import com.naiterui.ehp.bp.domain.NoticeInfo;
import com.naiterui.ehp.bp.domain.NoticeTopic;
import com.naiterui.ehp.bp.domain.education.EduAnalysis;
import com.naiterui.ehp.bp.domain.education.EduInfo;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.biz.AppJumpProtocol;
import com.naiterui.ehp.bp.utils.biz.TitleUtil;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.qr.WeiXinEncrypUtil;
import com.naiterui.ehp.bs.doctor.dao.IBannerInfoDao;
import com.naiterui.ehp.bs.doctor.dao.IBannerLabelDao;
import com.naiterui.ehp.bs.doctor.dao.IDepartmentDao;
import com.naiterui.ehp.bs.doctor.dao.IDoctorDao;
import com.naiterui.ehp.bs.doctor.dao.IDrConsultCommentDao;
import com.naiterui.ehp.bs.doctor.dao.IDrNoticeInfoDao;
import com.naiterui.ehp.bs.doctor.dao.IEduDao;
import com.naiterui.ehp.bs.doctor.dao.IHospitalDao;
import com.naiterui.ehp.bs.doctor.dao.IMessagePushHistoryDao;
import com.naiterui.ehp.bs.doctor.dao.INoticeInfoDao;
import com.naiterui.ehp.bs.doctor.dao.INoticeTopicDao;
import com.naiterui.ehp.bs.doctor.dao.mongo.AdBannerReadDao;
import com.naiterui.ehp.bs.doctor.dao.mongo.AdNoticeReaderDao;
import com.naiterui.ehp.bs.doctor.domain.DoctorLabel;
import com.naiterui.ehp.bs.doctor.domain.DrNoticeInfo;
import com.naiterui.ehp.bs.doctor.exception.ExceptionCodes;
import com.naiterui.ehp.bs.doctor.fegin.EsignFeginClient;
import com.naiterui.ehp.bs.doctor.fegin.RecomFeginClient;
import com.naiterui.ehp.bs.doctor.fegin.VideoConsultFeignClient;
import com.naiterui.ehp.bs.doctor.fegin.WeixinFeignClient;
import com.naiterui.ehp.bs.doctor.prodocl.BannerRead;
import com.naiterui.ehp.bs.doctor.prodocl.NoticeReader;
import com.naiterui.ehp.bs.doctor.remote.IAdRemoter;
import com.naiterui.ehp.bs.doctor.repository.IConsultSessionRepository;
import com.naiterui.ehp.bs.doctor.repository.IDrMessageConsultOrderRepository;
import com.naiterui.ehp.bs.doctor.repository.IPatientPersonDoctorRepository;
import com.naiterui.ehp.bs.doctor.service.IDoctorCertificateVoucherService;
import com.naiterui.ehp.bs.doctor.service.IDoctorService;
import com.naiterui.ehp.bs.doctor.service.IIndexService;
import com.naiterui.ehp.bs.doctor.utils.AppSpreadDataUtil;
import com.naiterui.ehp.bs.doctor.utils.CmsServiceUtil;
import com.naiterui.ehp.bs.doctor.utils.IMnoticeUtil;
import com.naiterui.ehp.bs.doctor.utils.ImageUrlUtil;
import com.naiterui.ehp.bs.doctor.utils.PropertyValueConstants;
import com.naiterui.ehp.bs.doctor.utils.RedisUtils;
import com.naiterui.ehp.bs.doctor.utils.UrlUtil;
import com.naiterui.ehp.bs.doctor.vo.BannerShareVO;
import com.naiterui.ehp.bs.doctor.vo.BannerVO;
import com.naiterui.ehp.bs.doctor.vo.BaseInfoVO;
import com.naiterui.ehp.bs.doctor.vo.CustomNoticeInfo;
import com.naiterui.ehp.bs.doctor.vo.LateNoticeVO;
import com.naiterui.ehp.bs.doctor.vo.NoticeListTypeVO;
import com.naiterui.ehp.bs.doctor.vo.NoticePageVO;
import com.naiterui.ehp.bs.doctor.vo.SpreadAppVo;
import com.naiterui.ehp.bs.doctor.vo.SpreadBaseVo;
import com.naiterui.ehp.bs.doctor.vo.SpreadDoctorVo;
import com.naiterui.ehp.bs.doctor.vo.SpreadPatientVo;
import com.naiterui.ehp.bs.doctor.vo.SpreadVo;
import com.naiterui.ehp.bs.doctor.vo.StartInfoVO;
import com.naiterui.ehp.bs.doctor.vo.UserCenterVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.util.HtmlUtils;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
public class AdIndexServiceImpl implements IIndexService {
    /**
     * cms端服务地址
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(AdIndexServiceImpl.class);

    @Value("${ehp.domain.img}")
    private String imgDomain;
    @Autowired
    private IDoctorService doctorService;
    @Autowired
    private IDepartmentDao departmentDao;
    @Autowired
    private IHospitalDao hospitalDao;
    @Autowired
    private IBannerInfoDao bannerInfoDao;
    @Autowired
    private IMessagePushHistoryDao messagePushHistoryDao;
    @Autowired
    private INoticeInfoDao noticeInfoDao;
    @Autowired
    private INoticeTopicDao noticTopicDao;
    @Autowired
    private AdNoticeReaderDao adNoticeReaderDao;
    @Autowired
    private IDrConsultCommentDao drConsultCommentDao;
    @Autowired
    private IDoctorDao doctorDao;
    @Autowired
    private AdBannerReadDao adBannerReadDao;
    @Autowired
    private IDoctorCertificateVoucherService doctorCertificateVoucherService;
    @Autowired
    private IEduDao eduDao;

    @Autowired
    private IBannerLabelDao bannerLabelDao;
    @Autowired
    private IDrNoticeInfoDao drNoticeInfoDao;
    @Autowired
    private IAdRemoter remoter;
    @Autowired
    private IIndexService indexService;

    @Autowired
    private EsignFeginClient esignFeginClient;
    @Autowired
    private RecomFeginClient recomFeginClient;
    @Autowired
    private IPatientPersonDoctorRepository patientPersonDoctorRepository;
    @Autowired
    private IConsultSessionRepository consultSessionRepository;
    @Autowired
    private VideoConsultFeignClient videoConsultFeignClient;
    @Autowired
    private IDrMessageConsultOrderRepository drMessageConsultOrderRepository;
    @Autowired
    private WeixinFeignClient weixinFeignClient;

    @Override
    public SpreadVo findSpreadByDoctorId(Long doctorId) throws BusinessException {

        // 1.获取医生信息
        Doctor doctor = getSpreadDoctorInfo(doctorId);

        // 2.获取分享基本信息
        SpreadBaseVo base = getSpreadInfo(doctor);
        SpreadVo vo = new SpreadVo();
        vo.copyBasePro(base);

        SpreadPatientVo spreadPatient = new SpreadPatientVo();

        // 医生未认证成功返回小程序二维码图片
        String spreadPtUrl;
        String spreadPtWxMaUrl = null;
        if (doctor.getStatus() != Doctor.AUTH_STATUS_SUCCESS) {
            spreadPtUrl = imgDomain + ConfigUtil.getString("ehp.miniapp.qrcode");
        } else {
            spreadPtUrl = getSpreadPatientUrl(doctorId);
            spreadPtWxMaUrl = getWxaSpreadPatientUrl(doctorId);
            if (spreadPtUrl == null) {
                LOGGER.error("获取医生推广患者的二维码为空,doctorId=" + doctorId);
                spreadPtUrl = getSpreadPatientUrl(doctorId);
            }
        }
        spreadPatient.setQrUrl(spreadPtUrl);
        vo.setSpreadPatient(spreadPatient);

        SpreadDoctorVo spreadDoctor = new SpreadDoctorVo();
        // 推广医生
        String spreadDrUrl = getSpreadDoctorUrl(doctorId);
        if (spreadDrUrl == null) {
            LOGGER.error("获取医生推广医生的二维码为空,doctorId=" + doctorId);
            spreadDrUrl = getSpreadDoctorUrl(doctorId);
        }
        spreadDoctor.setSpreadCode(doctor.getRecommCode());
        spreadDoctor.setQrUrl(spreadDrUrl);
        vo.setSpreadDoctor(spreadDoctor);
        vo.setSpreadDrUrl(AppSpreadDataUtil.getSpreadDrUrl(doctorId));
        vo.setSpreadPtUrl(AppSpreadDataUtil.getSpreadPtUrl(doctorId));
        vo.setSpreadPtWxMaUrl(spreadPtWxMaUrl);

        return vo;
    }


    @Override
    public SpreadAppVo getAppSpreadInfo(Long doctorId, int type) throws BusinessException {

        // 1.获取医生信息
        Doctor doctor = getSpreadDoctorInfo(doctorId);

        // 2.获取分享基本信息
        SpreadBaseVo base = getSpreadInfo(doctor);
        SpreadAppVo vo = new SpreadAppVo();
        vo.copyBasePro(base);

        // 4.设置二维码
        if (type == PropertyValueConstants.APP_DOCTOR_2_DOCTOR_TYPE) {
            String spreadDrUrl = getSpreadDoctorUrl(doctorId);
            if (spreadDrUrl == null) {
                LOGGER.error("获取医生推广医生的二维码为空,doctorId=" + doctorId);
                spreadDrUrl = getSpreadDoctorUrl(doctorId);
            }
            vo.setSpreadQrUrl(spreadDrUrl);
            vo.setSpreadType(1);
        } else if (type == PropertyValueConstants.APP_DOCTOR_2_PATIENT_TYPE) {// 患者
            String spreadPtUrl = getSpreadPatientUrl(doctorId);
            if (spreadPtUrl == null) {
                LOGGER.error("获取医生推广患者的二维码为空,doctorId=" + doctorId);
                spreadPtUrl = getSpreadPatientUrl(doctorId);
            }
            vo.setSpreadQrUrl(spreadPtUrl);
            vo.setSpreadType(2);
        }

        return vo;
    }

    /**
     * @deprecated 业务即将废弃，使用小程序二维码(需配合客户端调整，直接展示小程序二维码图片URL后可废弃)
     * 获取医生推广患者二维码（公众号）
     * @param doctorId
     * @return
     */
    @Deprecated
    private String getSpreadPatientUrl(Long doctorId) {

        try {
            String ptSpreadCodeKey = getPtSpreadCodeKey(doctorId);
            Object cachePtUrl = RedisUtils.get(ptSpreadCodeKey);
            if (cachePtUrl != null) {
                LOGGER.info("从患者中将患者二维码返回" + cachePtUrl);
                return (String) cachePtUrl;
            }
            // 推广患者
            //String patientUrl = remoter.getInviteCodeUrl(PaQrCodeEnum.INVITE, doctorId);
            String ptCodeUrl = remoter.getInviteCodeUrl(PaQrCodeEnum.INVITE, doctorId);
            if (ptCodeUrl != null) {
                RedisUtils.set(ptSpreadCodeKey, ptCodeUrl, 24 * 60 * 60);
            }
            return ptCodeUrl;
        } catch (Exception e) {

            LOGGER.error("获取医生推广患者的二维码为异常,doctorId=" + doctorId, e);
            return null;
        }
    }

    /**
     * 获取医生推广患者二维码(小程序)
     * @param doctorId
     * @return
     */
    private String getWxaSpreadPatientUrl(Long doctorId) {

        try {
            String ptSpreadCodeKey = getPtSpreadCodeWxaKey(doctorId);
            Object cachePtUrl = RedisUtils.get(ptSpreadCodeKey);
            if (cachePtUrl != null) {
                LOGGER.info("从患者中将患者微信小程序二维码返回" + cachePtUrl);
                return (String) cachePtUrl;
            }
            // 推广患者
            String ptCodeUrl = weixinFeignClient.miniappQrcode(PaQrCodeEnum.INVITE.getValue() + doctorId, null);
            if (ptCodeUrl != null) {
                RedisUtils.set(ptSpreadCodeKey, ptCodeUrl, 24 * 60 * 60);
            }
            return ptCodeUrl;
        } catch (Exception e) {

            LOGGER.error("获取医生推广患者的微信小程序二维码为异常,doctorId=" + doctorId, e);
            return null;
        }
    }

    private String getPtSpreadCodeKey(Long doctorId) {
        return PropertyValueConstants.SPREAD_PT_URL_KEY + doctorId;
    }

    /**
     * 微信小程序二维码缓存Key
     * @param doctorId
     * @return
     */
    private String getPtSpreadCodeWxaKey(Long doctorId) {
        return PropertyValueConstants.SPREAD_PT_WXA_URL_KEY + doctorId;
    }

    // 获取医生推广医生二维码
    private String getSpreadDoctorUrl(Long doctorId) {

        String baseDoctorUrl = ConfigUtil.getString("weixin.spread.doctor.url");
        return WeiXinEncrypUtil.encryUrl(baseDoctorUrl, doctorId, CommonConstant.DOCTOR_SPREAD_TYPE_DOCTOR);

    }

    // 获取医生是否可以推广，如果可以推广返回医生信息，否则抛出异常
    private Doctor getSpreadDoctorInfo(Long doctorId) throws BusinessException {

        Doctor doctor = doctorService.getDoctorById(doctorId);

        if (doctor == null) {
            throw new BusinessException(ExceptionCodes.DOCTORID_NOT_EXITS);
        }

        return doctor;
    }

    // 获取医生的基本信息
    private SpreadBaseVo getSpreadInfo(Doctor doctor) throws BusinessException {
        if (doctor == null) {
            LOGGER.warn("医生账户不存在");
            throw new BusinessException(ExceptionCodes.DOCTORID_NOT_EXITS);
        }
        SpreadBaseVo vo = new SpreadBaseVo();

        vo.setName(doctor.getName());
        Integer status = doctor.getStatus();
        if (status == Doctor.AUTH_STATUS_SUCCESS && !StringUtils.isEmpty(doctor.getHeadUrl())) {
            vo.setIconUrl(ImageUrlUtil.getImagePath(doctor.getHeadUrl()));
        }
//        else {
//            // 未认证医生设置默认图片
//            vo.setIconUrl(ConfigUtil.getString("dr.defualt.head"));
//        }

        // 设置职称
        if (doctor.getTitleId() != null) {
            String title = TitleUtil.getTitle(doctor.getTitleId());
            vo.setTitle(title);
        }

        // 设置科室
        String department = "";
        if (doctor.getDepartmentId() != null) {
            if (doctor.getDepartmentId().equals(0)) {
                department = doctor.getCustomDepartment();
            } else {
                Department departmentObj = departmentDao.get(doctor.getDepartmentId());
                if (departmentObj != null) {
                    department = departmentObj.getName();
                }
            }
        }
        vo.setDepartment(department);

        String hospital = "";
        if (doctor.getHospitalId() != null) {
            if (doctor.getHospitalId().equals(0)) {
                hospital = doctor.getHospitalName();
            } else {
                Hospital hospitalObj = hospitalDao.get(doctor.getHospitalId());
                if (hospitalObj != null) {
                    hospital = hospitalObj.getName();
                }
            }
        }
        vo.setHospital(hospital);
        // 注册时间
        vo.setRegistDate(DateUtil.formatDate(doctor.getCreatedAt(), DateUtil.YEAR_MONTH_FORMAT));

        vo.setStatus(doctor.getStatus());
        vo.setRecordStatus(doctor.getRecordStatus());
        vo.setExpertise(doctor.getExpertise());
        return vo;
    }

    @Override
    public BaseInfoVO getIndexBaseInfo(Long doctorId) throws BusinessException, JsonProcessingException {

        Doctor doctor = doctorService.get(doctorId);
        DoctorLabel label = new DoctorLabel(doctor.getLabelType());

        // 首页banner轮盘，显示数量、缓存时长
        int bannerCount = ConfigUtil.getInt("index.banner.count");
        int bannerTimeout = ConfigUtil.getInt("index.banner.timeout");
        bannerCount = bannerCount <= 0 ? 5 : bannerCount;
        bannerTimeout = bannerTimeout <= 0 ? 900 : bannerTimeout;

        List<BannerVO> bannerVOList = (List<BannerVO>) RedisUtils.get(PropertyValueConstants.getDoctorBannerCache(doctorId));
        if (CollectionUtil.isEmpty(bannerVOList)) {
            bannerVOList = new ArrayList<>();
            List<BannerInfo> bannerList = bannerInfoDao.getBannerInfo();
            if (CollectionUtil.isNotEmpty(bannerList)) {
                for (BannerInfo bannerInfo : bannerList) {
                    if (bannerVOList.size() > bannerCount - 1) {
                        break;
                    }
                    if (bannerInfo.getIsLabel()) {
                        List<Long> ids = bannerLabelDao.getLabelIds(bannerInfo.getId());
                        if (ids.size() > 0) {
                            // 是否要展示当前banner
                            // 根据医生id及bannerI判断，该医生是否包含此标签，是否要展示当前banner
                            Boolean result = CmsServiceUtil.drContainLabelId(doctorId, ids);
                            if (!result) {
                                continue;
                            }
                        }
                    }
                    // APP端跳转统一规范
                    BannerVO tempBannerVO = new BannerVO();
                    String imgUrl = bannerInfo.getImgUrl();
                    tempBannerVO.setImageUrl(ImageUrlUtil.genBannerPath(imgUrl));
                    tempBannerVO.setBackColor(bannerInfo.getBackColor());
                    Integer share = (null != bannerInfo.getShare() && !bannerInfo.getShare()) ? NoticeInfo.SHART_N : NoticeInfo.SHARE_Y;
                    BannerShareVO shareVO = new BannerShareVO(bannerInfo.getTitle(), share);
                    if (bannerInfo.getIsExternal() == BannerInfo.IS_EXTERNAL_Y && !StringUtils.isBlank(bannerInfo.getTargetUrl())) {
                        tempBannerVO.setTargetUrl(AppJumpProtocol.DR_WEB.parse(UrlUtil.medliveConvert(bannerInfo.getTargetUrl(), doctorId), shareVO));
                    }
                    String versionCode = imgUrl.substring(imgUrl.lastIndexOf("/") + 1, imgUrl.lastIndexOf("."));
                    tempBannerVO.setVersionCode(versionCode);
                    bannerVOList.add(tempBannerVO);
                }
            }
            // 缓存处理
            RedisUtils.set(PropertyValueConstants.getDoctorBannerCache(doctorId), bannerVOList, bannerTimeout);
        }

        List<BannerVO> layerVOList = (List<BannerVO>) RedisUtils.get(PropertyValueConstants.getDoctorLayerCache(doctorId));
        if (CollectionUtil.isEmpty(layerVOList)) {
            layerVOList = new ArrayList<>();
            BannerInfo layerInfo = bannerInfoDao.getLayerInfo();
            LOGGER.info("layerInfo：{}", layerInfo);
            // int isRead = BannerVO.IS_READ_N; //未读
            if (null != layerInfo) {
                /*
                BannerRead bannerRead = bannerReadDao.getBannerByConditions(doctorId, layerInfo.getDoctorId());
                if(bannerRead!=null){
                    isRead = BannerVO.IS_READ_Y; //已读
                }
                */
                // 是否要展示当前浮层，不带标签的浮层默认展示
                Boolean display = true;
                if (layerInfo.getIsLabel()) {
                    // 带标签的浮层默认不展示
                    display = false;
                    List<Long> ids = bannerLabelDao.getLabelIds(layerInfo.getId());
                    if (ids.size() > 0) {
                        // 根据医生id及bannerI判断 该医生是否包含此标签，是否展示当前浮层
                        display = CmsServiceUtil.drContainLabelId(doctorId, ids);
                    }
                }
                if (display) {
                    BannerVO tempBannerVO = new BannerVO();
                    // APP端跳转统一规范
                    String imgUrl = layerInfo.getImgUrl();
                    tempBannerVO.setImageUrl(ImageUrlUtil.genBannerPath(imgUrl));
                    tempBannerVO.setBackColor(layerInfo.getBackColor());
                    Integer share = (null != layerInfo.getShare() && !layerInfo.getShare()) ? NoticeInfo.SHART_N : NoticeInfo.SHARE_Y;
                    BannerShareVO shareVO = new BannerShareVO(layerInfo.getTitle(), share);
                    if (layerInfo.getIsExternal() == BannerInfo.IS_EXTERNAL_Y && !StringUtils.isBlank(layerInfo.getTargetUrl())) {
                        tempBannerVO.setTargetUrl(AppJumpProtocol.DR_WEB.parse(UrlUtil.medliveConvert(layerInfo.getTargetUrl(), doctorId), shareVO));
                    }
                    String versionCode = imgUrl.substring(imgUrl.lastIndexOf("/") + 1, imgUrl.lastIndexOf("."));
                    tempBannerVO.setVersionCode(versionCode);
                    layerVOList.add(tempBannerVO);
                }
            }
            // 缓存处理
            RedisUtils.set(PropertyValueConstants.getDoctorLayerCache(doctorId), layerVOList, bannerTimeout);

        }

        // v2.3获取账户可提现积分、好评数
        //int applyingPoint = this.pointService.findApplyingPointByDoctorId(doctorId);

        // TODO 星级记录数
        int commentCount = (int) drConsultCommentDao.getCommentCount(doctorId);

        BaseInfoVO baseInfoVO = new BaseInfoVO();
        baseInfoVO.setStatus(doctor.getStatus());
        baseInfoVO.setDoctorId(doctorId);
        String headUrl = doctor.getHeadUrl();
        if (StringUtils.isNotBlank(headUrl)) {
            // 默认头像
            baseInfoVO.setHeaderImageUrl(ImageUrlUtil.getImagePath(UserCenterVO.DEFAULT_HEAD_IMG));
            if (doctor.getStatus() == Doctor.AUTH_STATUS_SUCCESS) {
                baseInfoVO.setHeaderImageUrl(ImageUrlUtil.getImagePath(headUrl));
            }
        }
        baseInfoVO.setBanner(bannerVOList);
        baseInfoVO.setRecomTrialTimes(0);// 推荐用药试用次数

        //baseInfoVO.setApplyingPoint(applyingPoint);
        baseInfoVO.setCommentCount(commentCount);
        baseInfoVO.setLayer(layerVOList);
        // V2.5.0 添加推荐购药处方笺必要信息
        baseInfoVO.setName(doctor.getName());
        baseInfoVO.setDepartmentId(doctor.getDepartmentId());

        // 添加医生备案状态
        baseInfoVO.setRecordStatus(doctor.getRecordStatus());

        baseInfoVO.setIsPublic(label.getKeepRule() ? Doctor.PUBLIC_STATUS_YES : Doctor.PUBLIC_STATUS_NO);

        // 2.9 添加医生最近一次申请证书登记的手机号
        String lastCertificationPhone = doctorCertificateVoucherService.getLastCertificationPhone(doctorId);
        baseInfoVO.setLastCertificationPhone(lastCertificationPhone);// 最近一次申请证书登记的手机号

        // 2.12.0 健康检查医生标识
        Integer cityId = doctorService.getDoctorAreaCityId(doctorId, doctor);
        //baseInfoVO.setExamine(this.specialDoctorFunc.isExamineDoctor(doctorId, cityId) ? BaseInfoVO.EXAMINE_DOCTOR_FLAG_TRUE : BaseInfoVO
        // .EXAMINE_DOCTOR_FLAG_FALSE);
        baseInfoVO.setExamine(BaseInfoVO.EXAMINE_DOCTOR_FLAG_TRUE);
        LOGGER.info("检查入口；cityId：{}，isExamine：{}", cityId, baseInfoVO.getExamine());

        // 2.19.0医嘱处方标识
        baseInfoVO.setRecordRecom(label.getRecordRecom() ? 1 : 0);
        // 2.19加在这里主诉和既往史必填标识
        baseInfoVO.setRequiredFlag(remoter.getRequiredFlag());

        //是否安全用药范围医生
        baseInfoVO.setRecomSafe(label.getRecomSafe() ? 1 : 0);
        // 科室-2.19
        Integer departmentId = doctor.getDepartmentId();
        int departmentParentId = 0;
        if (departmentId != null) {
            if (departmentId == 0) {
                baseInfoVO.setDepartmentName(doctor.getCustomDepartment());// 自定义可是名
            } else {
                // 科室名称
                Department department = departmentDao.get(departmentId);
                baseInfoVO.setDepartmentName(department.getName());
                departmentParentId = department.getParentId();
            }
        }

        //父级科室或自定义科室
        String firstDepartmentName = baseInfoVO.getDepartmentName();
        if (departmentParentId != 0) {
            Department parentDepartment = departmentDao.get(departmentParentId);
            if (parentDepartment != null) {
                firstDepartmentName = parentDepartment.getName();
            }
        }
        baseInfoVO.setFirstDepartmentName(firstDepartmentName);
        // 医院-2.19
        Integer hospitalId = doctor.getHospitalId();
        if (hospitalId != null) {
            if (hospitalId == 0) {
                baseInfoVO.setHospitalName(doctor.getHospitalName());
            } else {
                Hospital hospital = hospitalDao.getHospitalById(hospitalId);
                baseInfoVO.setHospitalName(hospital.getName());
            }
        }
        // 最新一条公告或消息-2.21添加
        LateNoticeVO lateTitle = null;
        try {
            lateTitle = indexService.getLateNotice(doctorId);
        } catch (Exception e) {
            LOGGER.info("查询最近一条公告或通知错误,message:{}", e.getMessage());
        }
        baseInfoVO.setLateTitle(lateTitle);

        baseInfoVO.setShowCommission(0);
        baseInfoVO.setShowGoodsCommission(0);

        //提交备案或者备案通过后获取医生实名状态
        if (Doctor.AUTH_STATUS_SUCCESS == doctor.getStatus()) {
            //获取实名认证状态
            EsignDoctorBO bo = esignFeginClient.getEsignInfo(doctorId);
            baseInfoVO.setRealnameStatus(bo.getAuthStatus());
        }

        // 处方通过率
        DrBaseBusinessDataBO baseBusinessDataBO = recomFeginClient.getDrBaseBusinessData(doctorId);
        // 邀请患者数
        baseInfoVO.setPersonalPatientNum(patientPersonDoctorRepository.getTotalPatientCount(doctorId));
        baseInfoVO.setRecomAuditRate(baseBusinessDataBO.getRecomAuditRate());
        // 累计处理求药数
        baseInfoVO.setRequireRecomNum(null == baseBusinessDataBO.getRequireRecomNum() ? 0 : baseBusinessDataBO.getRequireRecomNum());
        // 待处理求药数
        baseInfoVO.setUntreatedRequireNum(null == baseBusinessDataBO.getUntreatedRequireNum() ? 0 : baseBusinessDataBO.getUntreatedRequireNum());
        // 累计处方数量
        baseInfoVO.setMedicationRecomNum(null == baseBusinessDataBO.getMedicationRecomNum() ? 0 : baseBusinessDataBO.getMedicationRecomNum());
        //设置快捷登录状态
        String fastLoginStatusStr = RedisUtils.getString(PropertyValueConstants.FAST_LOGIN_STATUS_CACHE + doctorId);
        // 待接诊视频问诊数
        baseInfoVO.setVideoConsultNum(Optional.ofNullable(videoConsultFeignClient.getVideoConsultCountByStatus(doctorId, DrVideoConsult.VIDEO_CONSULT_STATUS_TO_TREAT)).orElse(0));
        Integer videoConsultCount = Optional.ofNullable(videoConsultFeignClient.getVideoConsultCountByStatus(doctorId, DrVideoConsult.VIDEO_CONSULT_STATUS_ALL)).orElse(0);
        Integer textConsultCount = Optional.ofNullable(consultSessionRepository.findCountByDoctorId(doctorId)).orElse(0);
        // 累计问诊数量
        baseInfoVO.setConsultNum(textConsultCount + videoConsultCount);
        // 累计收入(图文收入+视频收入)
        List<DrMessageConsultOrder> textConsultOrders = drMessageConsultOrderRepository.findByDoctorId(doctorId);
        Integer allConsultPrice = textConsultOrders.stream().mapToInt(o -> o.getPrice()).sum();
        List<VideoConsultBO> videoConsultOrders = videoConsultFeignClient.getOrderByDoctorId(doctorId);
        allConsultPrice += videoConsultOrders.stream().filter(v -> DrVideoConsult.VIDEO_CONSULT_PAY_SUCCESS == v.getPayStatus()).mapToInt(VideoConsultBO::getPrice).sum();
        baseInfoVO.setAllConsultPrice(allConsultPrice);

        if (StringUtils.isBlank(fastLoginStatusStr)) {
            baseInfoVO.setFastLoginStatus(0);
        } else {
            baseInfoVO.setFastLoginStatus(Integer.parseInt(fastLoginStatusStr));
        }
        baseInfoVO.setTitleId(doctor.getTitleId());
        baseInfoVO.setTitle(TitleUtil.getTitle(doctor.getTitleId()));
        baseInfoVO.setPhone(doctor.getPhone());
        return baseInfoVO;
    }


    @Override
    public PageVO<MessagePushHistory> getUserDynamics(Long doctorId, PageParamVO page) {
        Page<MessagePushHistory> resultPage = messagePushHistoryDao.findPagePaList(doctorId, page.getPage(), page.getNum(), new Date());
        return CustomizedPageConvertor.pageConvert(resultPage);
    }

    /*
     * 获取系统公告分页数据
     * IIndexService.getNoticePage()
     */
    @Override
    public PageVO<NoticePageVO> getNoticePage(Long doctorId, Integer sort, String limitTime, Long topic, PageParamVO pageParam)
            throws BusinessException {
        // Page<NoticeInfo> result = new Page<NoticeInfo>();
        Doctor doctor = doctorDao.get(doctorId);

        if (null == doctor) {
            LOGGER.error(" getNoticePage ERROR ; doctor not exist : doctorId={}", doctorId);
            throw new BusinessException(ExceptionCodes.DOCTOR_ACC_NOT_EXITS);
        }

        Page<CustomNoticeInfo> result = noticeInfoDao.getNoticePage(pageParam, limitTime, topic, doctor);

        Page<NoticePageVO> resultPage = new Page<>();
        resultPage.setPageNo(result.getPageNo());
        resultPage.setPageSize(result.getPageSize());
        resultPage.setTotalCount(result.getTotalCount());

        List<NoticePageVO> resultList = new ArrayList<>();
        if (null != result.getResult() && !result.getResult().isEmpty()) {
            // cms公告id
            List<Long> cmsIdList = new ArrayList<>();
            // 自定义公告id
            List<Long> drIdList = new ArrayList<>();
            for (CustomNoticeInfo info : result.getResult()) {
                if (info.getTableType() == CustomNoticeInfo.TABLE_TYPE_CMS) {
                    cmsIdList.add(info.getId());
                } else if (info.getTableType() == CustomNoticeInfo.TABLE_TYPE_DR) {
                    drIdList.add(info.getId());
                }
            }
            // cms公告
            Map<Long, NoticeInfo> cmsNoticeInfoMap = noticeInfoDao.getNoticeInfoByList(cmsIdList);
            // 自定义公告
            Map<Long, DrNoticeInfo> drNoticeInfoMap = drNoticeInfoDao.getDrNoticeInfoByList(drIdList);
            // 公告主题
            Map<Long, NoticeTopic> topicMap = noticTopicDao.getTopicMap();

            for (CustomNoticeInfo customInfo : result.getResult()) {
                // 构建cmsVO
                if (customInfo.getTableType() == CustomNoticeInfo.TABLE_TYPE_CMS) {
                    NoticeInfo noticeInfo = cmsNoticeInfoMap.get(customInfo.getId());
                    NoticePageVO noticePageVO = new NoticePageVO(noticeInfo);
                    // 公告主题
                    NoticeTopic tempTopic = topicMap.get(noticeInfo.getTopicId());
                    noticePageVO.setTopic(null == tempTopic ? "" : tempTopic.getName());
                    // 若为非图文类型公告，则列表页返回正文
                    if (NoticeInfo.NOTICE_TYPE_LINK_URL == noticeInfo.getNoticeType()) {
                        noticePageVO.setContent(UrlUtil.medliveConvert(noticeInfo.getContent(), doctorId));
                    } else if (NoticeInfo.NOTICE_TYPE_PIC_TEXT != noticeInfo.getNoticeType()) {
                        noticePageVO.setContent(noticeInfo.getContent());
                    }
                    resultList.add(noticePageVO);

                    // 处理阅读数(纯文本类 公告)
                    if (NoticeInfo.NOTICE_TYPE_PLAIN_TEXT == noticeInfo.getNoticeType()) {
                        handleReadNum(doctorId, noticeInfo);
                    }
                } else if (customInfo.getTableType() == CustomNoticeInfo.TABLE_TYPE_DR) {
                    DrNoticeInfo drNoticeInfo = drNoticeInfoMap.get(customInfo.getId());
                    NoticePageVO noticePageVO = new NoticePageVO();
                    // 公告主题
                    NoticeTopic tempTopic = topicMap.get(drNoticeInfo.getTopicId());
                    noticePageVO.setTopic(null == tempTopic ? "" : tempTopic.getName());
                    noticePageVO.setId(drNoticeInfo.getId());
                    noticePageVO.setNoticeType(drNoticeInfo.getNoticeType());
                    noticePageVO.setStartTime(drNoticeInfo.getStartTime());
                    noticePageVO.setTitle(drNoticeInfo.getTitle());
                    // 图片处理
                    if (StringUtils.isNotEmpty(drNoticeInfo.getCoverImg())) {
                        noticePageVO.setCoverImg(ImageUrlUtil.genNoticePath(drNoticeInfo.getCoverImg()));
                        noticePageVO.setShowCoverImg(NoticeInfo.NOTICE_COVER_HIDDEN);
                    }
                    // 若为非图文类型公告，则列表页返回正文
                    if (NoticeInfo.NOTICE_TYPE_LINK_URL == drNoticeInfo.getNoticeType()) {
                        noticePageVO.setContent(UrlUtil.medliveConvert(drNoticeInfo.getContent(), doctorId));
                    } else if (NoticeInfo.NOTICE_TYPE_PIC_TEXT != drNoticeInfo.getNoticeType()) {
                        noticePageVO.setContent(drNoticeInfo.getContent());
                    }
                    resultList.add(noticePageVO);
                }

            }
        }

        // 处理公告页面内排序(默认1，1：正序，2：倒叙)
        if (null == sort || sort == 1) {
            Collections.reverse(resultList);
        }

        resultPage.setResult(resultList);

        return CustomizedPageConvertor.pageConvert(resultPage);
    }

    /*
     * 获取系统公告详情 IIndexService.getNoticeDetail()
     */
    @Override
    public NoticePageVO getNoticeDetail(Long doctorId, Long noticeId) throws BusinessException {

        NoticeInfo noticeInfo = noticeInfoDao.get(noticeId);
        if (null == noticeInfo) {
            LOGGER.error(" getNoticeDetail ERROR ; NoticeInfo not exist : noticeId={}", noticeId);
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }
        NoticePageVO noticePageVO = new NoticePageVO(noticeInfo);
        NoticeTopic tempTopic = noticTopicDao.get(noticeInfo.getTopicId());
        noticePageVO.setTopic(null == tempTopic ? "" : tempTopic.getName());
        noticePageVO.setContent(noticeInfo.getContent());
        noticePageVO.setDecodeContent(HtmlUtils.htmlUnescape(noticeInfo.getContent()));

        // 处理阅读数(非纯文本类 公告)
        if (null != doctorId && NoticeInfo.NOTICE_TYPE_PLAIN_TEXT != noticeInfo.getNoticeType()) {
            handleReadNum(doctorId, noticeInfo);
        }
        // 2.13
        // buttonComment app按钮文案
        if (StringUtils.isNotBlank(noticeInfo.getLinkComment())) {
            if (NoticeInfo.URL_TYPE_EDU.intValue() == noticeInfo.getUrlType().intValue()) {
                List<EduInfo> eduInfos = eduDao.getEduInfoByUrl(UrlUtil.urlEncode(noticeInfo.getUrlLink()));
                if (eduInfos.size() > 0) {
                    noticePageVO.setButtonComment(noticeInfo.getLinkComment());
                    // eduUrl 宣教地址
                    noticePageVO.setUrlType(NoticeInfo.URL_TYPE_EDU);
                    noticePageVO.setEduUrl(noticeInfo.getUrlLink());

                    EduInfo eduInfo = eduInfos.get(0);
                    // eduTitle 宣教标题
                    // eduOrigin 宣教来源
                    noticePageVO.setEduId(eduInfo.getId());
                    noticePageVO.setEduTitle(eduInfo.getEduTitle());
                    noticePageVO.setEduOrigin(eduInfo.getEduOrigin());
                    // 宣教id-阅读数
                    List<EduAnalysis> analysis = eduDao.getReadCount(eduInfo.getId(), doctorId);
                    LOGGER.info("根据宣教id及医生id 获取宣教的阅读量 analysis:{}", analysis);
                    // readCount 阅读数
                    if (analysis.size() <= 0) {
                        noticePageVO.setReadCount(0);
                    } else {
                        EduAnalysis eduAnalysis = analysis.get(0);
                        noticePageVO.setReadCount(eduAnalysis.getReadCount());
                    }
                }
            } else {
                noticePageVO.setButtonComment(noticeInfo.getLinkComment());
                noticePageVO.setUrlType(NoticeInfo.URL_TYPE_USER);
            }
        }
        return noticePageVO;
    }

    /**
     * 处理公告阅读数
     * IndexServiceImpl.handleReadNum()
     *
     * @param doctorId
     * @param noticeInfo
     * @Date 2016年3月30日
     * @since 2.3.0
     */
    private void handleReadNum(Long doctorId, NoticeInfo noticeInfo) {

        // mongo处理公告阅读数
        NoticeReader noticeReader = adNoticeReaderDao.getNoticeReader(noticeInfo.getId(), doctorId);

        if (null == noticeReader) {
            noticeReader = new NoticeReader();
            noticeReader.setNoticeId(noticeInfo.getId());
            noticeReader.setReader(doctorId);
            noticeReader.setReadTime(DateUtil.getCurrentFormatDateTime());
            adNoticeReaderDao.saveNoticeReader(noticeReader);
        }

    }

    /**
     * Banner图计数
     *
     * @param doctorId
     * @param bannerId
     * @Author YongYang
     * @Date 2016年6月24日
     * @see IIndexService#countBannerReadNum(java.lang.Long,
     * java.lang.Long)
     * @since 1.0.0
     */
    @Override
    public void countBannerReadNum(Long doctorId, Long bannerId) {
        BannerRead bannerRead = adBannerReadDao.getBannerByConditions(doctorId, bannerId);
        if (bannerRead == null) {
            bannerRead = new BannerRead();
            bannerRead.setBannerId(bannerId);
            bannerRead.setDoctorId(doctorId);
            bannerRead.setLastReadTime(DateUtil.getCurrentFormatDateTime());
            adBannerReadDao.save(bannerRead);
        }
    }

    @Override
    public StartInfoVO getStartInfo(Long doctorId) throws Exception {
        StartInfoVO resultVO = new StartInfoVO(new ArrayList<>());
        List<BannerVO> startup = new ArrayList<>();
        List<BannerInfo> bannerInfoList = bannerInfoDao.getBannerByType(BannerInfo.BANNER_TYPE_START);
        List<BannerInfo> canShowList = new ArrayList<>();
        if (null != bannerInfoList && bannerInfoList.size() > 0) {
            for (BannerInfo bannerInfo : bannerInfoList) {
                if (canShow(bannerInfo, doctorId)) {
                    canShowList.add(bannerInfo);
                }
            }
        }
        // 从可展示范围列表随机取一张进行返回
        if (canShowList.size() > 0) {
            int size = canShowList.size();
            int randomIndex = new SecureRandom().nextInt(size);
            BannerInfo resultBanner = canShowList.get(randomIndex);
            BannerVO vo = new BannerVO();
            vo.setImageUrl(ImageUrlUtil.genBannerPath(resultBanner.getImgUrl()));
            Integer share = (null != resultBanner.getShare() && !resultBanner.getShare()) ? NoticeInfo.SHART_N : NoticeInfo.SHARE_Y;
            BannerShareVO shareVO = new BannerShareVO(resultBanner.getTitle(), share);
            if (resultBanner.getIsExternal() == BannerInfo.IS_EXTERNAL_Y && !StringUtils.isEmpty(resultBanner.getTargetUrl())) {
                vo.setTargetUrl(AppJumpProtocol.DR_WEB.parse(UrlUtil.medliveConvert(resultBanner.getTargetUrl(), doctorId), shareVO));
            }
            startup.add(vo);
            resultVO.setStartup(startup);
        }
        return resultVO;
    }

    /**
     * 给定首页启动图活动是否可以在指定医生客户端展示
     * 注：仅限启动图可使用此方法
     * 逻辑如下：
     * 1、doctorId为空，banner非标签，可展示；
     * 2、doctorId为空，banner带标签，不可展示；
     * 3、doctorId非空，banner非标签，可展示；
     * 4、doctorId非空，banner带标签，根据双方标签交集判断是否展示；
     * IndexServiceImpl.canShow()
     *
     * @param bannerInfo
     * @param doctorId
     * @return
     * @author fangguanhong
     * @Date 2018年4月26日
     * @since 1.0.0
     */
    public boolean canShow(BannerInfo bannerInfo, Long doctorId) {
        boolean result = true;
        if (bannerInfo.getIsLabel()) {
            if (null != doctorId) {
                // 带标签的活动在可以拿到用户信息的情况下需要判断用户是否包含此活动所携带标签，以此判断是否可以显示此活动
                List<Long> ids = bannerLabelDao.getLabelIds(bannerInfo.getId());
                result = CmsServiceUtil.drContainLabelId(doctorId, ids);
            } else {
                // 带标签的活动在拿不到用户信息的情况下必定不展示
                result = false;
            }
        }
        return result;
    }

    @Override
    public List<NoticeListTypeVO> getNoticeListType(Long doctorId) throws Exception {
        List<NoticeListTypeVO> list = new ArrayList<>();
        Doctor doctor = doctorService.get(doctorId);
        // 公告类型
        Map<Long, NoticeTopic> map = noticTopicDao.getTopicMap();
        NoticeTopic systemTopic = map.get(NoticeListTypeVO.NOTICETYPE_SYSTEM);// 系统公告
        DrNoticeInfo drNotice = null;
        // 最近一条系统公告
        NoticeInfo systemNotice = noticeInfoDao.getLateNoticeInfo(doctor, systemTopic.getId());
        // 最近一条系统通知
        MessagePushHistory message = messagePushHistoryDao.getLateMessage(doctorId);
        if (systemNotice != null) {
            // 系统公告
            NoticeListTypeVO systemNoticeVO = new NoticeListTypeVO();
            systemNoticeVO.setNoticeType(NoticeListTypeVO.NOTICETYPE_SYSTEM);
            systemNoticeVO.setLogo(ImageUrlUtil.genNoticePath(ConfigUtil.getString("notice.logo.system")));
            systemNoticeVO.setName(systemTopic.getName());
            systemNoticeVO.setTitle(systemNotice.getTitle());// 标题内容
            systemNoticeVO.setSendTime(systemNotice.getStartTime().getTime());// 发送时间
            // linkUrl
            String systemTargetUrl = IMnoticeUtil.getTargetUrl(systemTopic);
            String systemLinkUrl = AppJumpProtocol.DR_WEB.parse(systemTargetUrl);
            systemNoticeVO.setLinkUrl(systemLinkUrl);
            list.add(systemNoticeVO);
        }

        if (message != null) {
            // 系统通知
            NoticeListTypeVO messageVO = new NoticeListTypeVO();
            messageVO.setNoticeType(NoticeListTypeVO.NOTICETYPE_DYNAMIC);
            messageVO.setLogo(ImageUrlUtil.genNoticePath(ConfigUtil.getString("notice.logo.dynamic")));
            messageVO.setName(ConfigUtil.getString("notice.dynamic.text"));
            messageVO.setTitle(message.getContent());// 标题内容
            messageVO.setSendTime(message.getCreatedAt().getTime());// 发送时间
            // linkUrl
            messageVO.setLinkUrl(AppJumpProtocol.DR_DYNAMIC.parse());
            list.add(messageVO);
        }

        return list;
    }

    @Override
    public LateNoticeVO getLateNotice(Long doctorId) throws Exception {
        Doctor doctor = doctorService.get(doctorId);
        // 最近一条通用公告
        NoticeInfo notice = noticeInfoDao.getLateNoticeInfo(doctor, null);
        // 新手教程
        //DrNoticeInfo drNotice = this.drNoticeInfoDao.getNewDoctorNotice(doctorId, DrNoticeInfo.MSG_SCENE_NEW_DOCTOR);
        // 最近一条系统通知
        MessagePushHistory message = messagePushHistoryDao.getLateMessage(doctorId);
        // 公告类型
        Map<Long, NoticeTopic> map = noticTopicDao.getTopicMap();
        //NoticeTopic newTopic = map.get(LateNoticeVO.NOTICETYPE_NEW);// 行业新闻
        //NoticeTopic doctorTopic = map.get(LateNoticeVO.NOTICETYPE_DOCTOR);// 医生学院
        NoticeTopic systemTopic = map.get(LateNoticeVO.NOTICETYPE_SYSTEM);// 系统公告
        // 取时间最近一条消息
        String title = null;
        Long noticeType = null;
        String linkUrl = null;
        Long time = null;// 用于比较
        // 判断通用公告
        if (notice != null) {
            title = notice.getTitle();
            time = notice.getStartTime().getTime();

            if (notice.getTopicId().longValue() == systemTopic.getId().longValue()) {// 系统公告
                noticeType = LateNoticeVO.NOTICETYPE_SYSTEM;
                String systemTargetUrl = IMnoticeUtil.getTargetUrl(systemTopic);
                linkUrl = AppJumpProtocol.DR_WEB.parse(systemTargetUrl);
            }
        }

        // 判断系统通知
        if (message != null) {
            if (time != null) {
                if (time < message.getCreatedAt().getTime()) {
                    title = message.getContent();
                    time = message.getCreatedAt().getTime();
                    noticeType = LateNoticeVO.NOTICETYPE_DYNAMIC;
                    linkUrl = AppJumpProtocol.DR_DYNAMIC.parse();
                }
            } else {
                title = message.getContent();
                time = message.getCreatedAt().getTime();
                noticeType = LateNoticeVO.NOTICETYPE_DYNAMIC;
                linkUrl = AppJumpProtocol.DR_DYNAMIC.parse();
            }
        }
        LateNoticeVO lateVO = null;
        if (title != null) {
            lateVO = new LateNoticeVO();
            lateVO.setTitle(title);
            lateVO.setSendTime(time);
            lateVO.setNoticeType(noticeType);
            lateVO.setLinkUrl(linkUrl);

        }
        return lateVO;
    }
}
